<?php

namespace sdk;

// 常量定义
define('TOKEN', 'IntelliJourney');

define('APIURL', 'https://api.weixin.qq.com/cgi-bin');

class WeiXin {

    private $appName;
    private $appId;
    private $appSecret;

    public function __construct($appName, $appId, $appSecret) {
        $this->appName = $appName;
        $this->appId = $appId;
        $this->appSecret = $appSecret;
    }

    // 以下方法用来帮助第三方服务器与微信服务器交互
    public function valid() {
        $echoStr = $_GET["echostr"];

        //valid signature
        if ($this->checkSignature()) {
            echo $echoStr;
            exit;
        }
    }

    public function checkSignature() {
        // you must define TOKEN by yourself
        if (!defined("TOKEN")) {
            throw new Exception('TOKEN is not defined!');
        }

        $signature = $_GET["signature"];
        $timestamp = $_GET["timestamp"];
        $nonce = $_GET["nonce"];

        $tmpArr = array(TOKEN, $timestamp, $nonce);
        // use SORT_STRING rule
        sort($tmpArr, SORT_STRING);
        $tmpStr1 = implode($tmpArr);
        $tmpStr2 = sha1($tmpStr1);

        if ($tmpStr2 === $signature) {
            return true;
        } else {
            return false;
        }
    }

    // 以下方法用来帮助客户端浏览器与微信服务器交互
    public function getSignPackage() {
        $jsapiTicket = $this->getJsApiTicket();

        // 注意 URL 一定要动态获取，不能 hardcode.
        $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
        $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";

        $timestamp = time();
        $nonceStr = $this->createNonceStr();

        // 这里参数的顺序要按照 key 值 ASCII 码升序排序
        $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";

        $signature = sha1($string);

        $signPackage = array(
            "appId" => $this->appId,
            "nonceStr" => $nonceStr,
            "timestamp" => $timestamp,
            "url" => $url,
            "signature" => $signature,
            "rawString" => $string
        );
        return $signPackage;
    }

    private function createNonceStr($length = 16) {
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    private function getJsApiTicket() {
        // 打开以文件形式缓存的jsapi_ticket
        $data = json_decode(file_get_contents("../{$this->appName}_jsapi_ticket.json"));

        // 如果之前缓存的jsapi_ticket已经失效，则再次生成
        if ($data->expire_time < time()) {
            $access_token = $this->getAccessToken();
            // 用以下链接获取企业号的jsapi_ticket
            // $url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=$accessToken";
            $url = APIURL . "/ticket/getticket?type=jsapi&access_token=$access_token";
            $res = json_decode($this->httpRequest($url, 'GET'));
            $ticket = $res->ticket;
            if ($ticket) {
                $data->expire_time = time() + 7000;
                $data->jsapi_ticket = $ticket;
                $fp = fopen("../{$this->appName}_jsapi_ticket.json", "w");
                fwrite($fp, json_encode($data));
                fclose($fp);
            }
        } else {
            $ticket = $data->jsapi_ticket;
        }

        return $ticket;
    }

    public function getAccessToken() {
        // 打开以文件形式缓存的access token
        $cache_file = "../{$this->appName}_access_token.json";
        $data = json_decode(file_get_contents($cache_file));
        if ($data->expire_time < time()) {
            // 用以下链接获取企业号的access_token
            // $url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=$this->appId&corpsecret=$this->appSecret";
            $url = APIURL . "/token?grant_type=client_credential&appid=$this->appId&secret=$this->appSecret";
            $res = json_decode($this->httpRequest($url, 'GET'));
            $access_token = $res->access_token;
            if ($access_token) {
                // 缓存文件中记录的失效时间，比其实失效时间提早1600秒
                $data->expire_time = time() + $res->expires_in - 1600;
                $data->access_token = $access_token;
                $fp = fopen($cache_file, "w");
                fwrite($fp, json_encode($data));
                fclose($fp);
            }
        } else {
            $access_token = $data->access_token;
        }
        return $access_token;
    }

    public function getOauthAccessToken($code) {
        // 打开以文件形式缓存的oauth access token
        $cache_file = "../{$this->appName}_oauth_access_token.json";
        $data = json_decode(file_get_contents($cache_file));
        if ($data->expire_time < time()) {
            $url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=$this->appId&secret=$this->appSecret&code=$code&grant_type=authorization_code";
            $res = json_decode($this->httpRequest($url, 'GET'));
            $access_token = $res->access_token;
            if ($access_token) {
                // 缓存文件中记录的失效时间，比其实失效时间提早600秒
                $data->expire_time = time() + $res->expires_in - 600;
                $data->access_token = $access_token;
                $fp = fopen($cache_file, "w");
                fwrite($fp, json_encode($data));
                fclose($fp);
            }
        } else {
            $access_token = $data->access_token;
        }
        return $access_token;
    }

    public function getOauthOpenid($code) {
        $url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=$this->appId&secret=$this->appSecret&code=$code&grant_type=authorization_code";
        $res = json_decode($this->httpRequest($url, 'GET'));
        $openid = $res->openid;

        return $openid;
    }

    public function getCallbackIP() {
        $access_token = $this->getAccessToken();
        $url = APIURL . "/getcallbackip?access_token=$access_token";
        $res = $this->httpRequest($url, "GET");
        return $res;
    }

    public function getProfile($openid) {
        $access_token = $this->getAccessToken();
        $url = APIURL . "/user/info?access_token=$access_token&openid=$openid&lang=zh_CN";
        $profile = json_decode($this->httpRequest($url, "GET"));
        return $profile;
    }

    public function listShop($json_str) {
        $access_token = $this->getAccessToken();
        $url = APIURL . "/poi/getpoilist?access_token=$access_token";
        $shop_list = $this->httpRequest($url, "POST", $json_str);
        return $shop_list;
    }

    public function getShop($json_str) {
        $access_token = $this->getAccessToken();
        $url = APIURL . "/poi/getpoi?access_token=$access_token";
        $shop = $this->httpRequest($url, "POST", $json_str);
        return $shop;
    }

    public function createQRcodeUrl($json_str) {
        $access_token = $this->getAccessToken();
        $url = APIURL . "/qrcode/create?access_token=$access_token";

        $res = json_decode($this->httpRequest($url, "POST", $json_str));
        $qrcode_url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={$res->ticket}";

        return $qrcode_url;
    }

    public function createMenu($json_str) {
        $access_token = $this->getAccessToken();
        $url = APIURL . "/menu/create?access_token=$access_token";

        $json_res = $this->httpRequest($url, "POST", $json_str);
        return $json_res;
    }

    public function sendTemplateMessage($param) {
        $access_token = $this->getAccessToken();
        $url = APIURL . "/message/template/send?access_token=$access_token";

        $json_res = $this->httpRequest($url, "POST", json_encode($param));
        return $json_res;
    }

    public function startServiceNotification($openid, $duration, $cost, $service_id) {
        $param = array('touser' => $openid,
            'template_id' => 'EhuPn824rvGmAbp3xTs3SqiJHzP6SxGDH_q8hoQbY08',
            //'url' => 'http://wx.hui-dian.cn/shop.php',
            'data' => array(
                'first' => array(
                    'value' => '您已下单成功'
                ),
                'keyword1' => array(
                    'value' => '美甲'
                ),
                'keyword2' => array(
                    'value' => date('y-m-d H:i:s', time())
                ),
                'keyword3' => array(
                    'value' => "{$duration}小时"
                ),
                'keyword4' => array(
                    'value' => "{$cost}元"
                ),
                'remark' => array(
                    'value' => "美美的一天，从指尖开始！美单号为{$service_id}的服务开始了。"
                )
        ));
        $this->sendTemplateMessage($param);
    }

    public function saveMediaFile($media_id) {
        $access_token = $this->getAccessToken();
        $image_url = APIURL . "/media/get?access_token=$access_token&media_id=$media_id";
        $file_name = uniqid() . '.jpg';
        $image_full_name = '/var/tmp/' . $file_name;
        $cmd = 'curl -G "' . $image_url . '" > ' . $image_full_name;
        exec($cmd);
        return $image_full_name;
    }

    public function saveRemoteFile($image_url) {
        $file_name = uniqid() . '.jpg';
        $image_full_name = '/var/tmp/' . $file_name;
        $cmd = 'curl -G "' . $image_url . '" > ' . $image_full_name;
        exec($cmd);
        return $image_full_name;
    }

    public function uploadMediaFile($image_full_name) {
        $filedata = array("name" => "@" . $image_full_name);
        $access_token = $this->getAccessToken();
        $upload_url = APIURL . "/media/upload?access_token=$access_token&type=image";
        $res = json_decode($this->httpRequest($upload_url, 'POST', $filedata));
        return $res->media_id;
    }

    public function generateDownloadUrl($userid = 0, $fileid = null, $oper = '') {
        return Image::generateDownloadUrl($userid, $fileid, $oper);
    }

    /*
      // 按照预设的规则解释event_key
      public function processEventKey($event_name, $event_key) {
      switch ($event_name) {
      // subscribe事件的id，从第8位开始
      case 'subscribe':
      $first_part = substr($event_key, 8, -1);
      break;
      // scan事件的id，从第0位开始
      case 'SCAN':
      $first_part = substr($event_key, 0, -1);
      break;
      default:
      throw new Exception('unknown event name');
      }
      $last_part = substr($event_key, -1);

      $result = array();
      switch ($last_part) {
      // 角色为店主，相关编码为shop_id
      case 0:
      $result['shop_id'] = $first_part;
      $result['role'] = $last_part;
      break;
      // 角色为店员，相关编码为shop_id
      case 1:
      $result['shop_id'] = $first_part;
      $result['role'] = $last_part;
      break;
      // 角色为客户，相关编码为shop_id
      case 2:
      $result['shop_id'] = $first_part;
      $result['role'] = $last_part;
      break;
      // 角色为任意，相关编码为service_id
      case 9:
      $result['service_id'] = $first_part;
      $result['role'] = $last_part;
      break;
      default:
      throw new Exception('unknown event key');
      }
      return $result;
      }
     */

    // 回复用户文本消息
    public function responseTextXML($to_user_name, $from_user_name, $content_response) {
        //response parameters 
        $time = time();
        $text_template = "<xml>
                        <ToUserName><![CDATA[%s]]></ToUserName>
                        <FromUserName><![CDATA[%s]]></FromUserName>
                        <CreateTime>%s</CreateTime>
                        <MsgType><![CDATA[text]]></MsgType>
                        <Content><![CDATA[%s]]></Content>
                      </xml>";
        $resultStr = sprintf($text_template, $to_user_name, $from_user_name, $time, $content_response);
        echo $resultStr;
    }

    // 回复用户语音消息
    public function responseVoiceXML($to_user_name, $from_user_name, $media_id) {
        //response parameters 
        $time = time();
        $text_template = "<xml>
                        <ToUserName><![CDATA[%s]]></ToUserName>
                        <FromUserName><![CDATA[%s]]></FromUserName>
                        <CreateTime>%s</CreateTime>
                        <MsgType><![CDATA[voice]]></MsgType>
                        <Voice>
                                <MediaId><![CDATA[%s]]></MediaId>
                        </Voice>
                      </xml>";
        $resultStr = sprintf($text_template, $to_user_name, $from_user_name, $time, $media_id);
        echo $resultStr;
    }

    // 回复用户图像消息
    public function responseImageXML($to_user_name, $from_user_name, $media_id) {
        //response parameters 
        $time = time();
        $text_template = "<xml>
                        <ToUserName><![CDATA[%s]]></ToUserName>
                        <FromUserName><![CDATA[%s]]></FromUserName>
                        <CreateTime>%s</CreateTime>
                        <MsgType><![CDATA[image]]></MsgType>
                        <Image>
                                <MediaId><![CDATA[%s]]></MediaId>
                        </Image>
		      </xml>";
        $resultStr = sprintf($text_template, $to_user_name, $from_user_name, $time, $media_id);
        echo $resultStr;
    }

    // 回复用户视频消息
    public function responseVideoXML($to_user_name, $from_user_name, $media_id, $title, $description) {
        //response parameters 
        $time = time();
        $text_template = "<xml>
                        <ToUserName><![CDATA[%s]]></ToUserName>
                        <FromUserName><![CDATA[%s]]></FromUserName>
                        <CreateTime>%s</CreateTime>
                        <MsgType><![CDATA[video]]></MsgType>
                        <Video>
                        <MediaId><![CDATA[%s]]></MediaId>
                        <Title><![CDATA[%s]]></Title>
                        <Description><![CDATA[%s]]></Description>
                        </Video>
		      </xml>";
        $resultStr = sprintf($text_template, $to_user_name, $from_user_name, $time, $media_id, $title, $description);
        echo $resultStr;
    }

    // 回复用户音乐消息
    public function responseMusicXML($to_user_name, $from_user_name, $title, $description, $music_url, $HQ_music_url, $media_id) {
        //response parameters 
        $time = time();
        $text_template = "<xml>
                        <ToUserName><![CDATA[%s]]></ToUserName>
                        <FromUserName><![CDATA[%s]]></FromUserName>
                        <CreateTime>%s</CreateTime>
                        <MsgType><![CDATA[music]]></MsgType>
                        <Music>
                        <Title><![CDATA[%s]]></Title>
                        <Description><![CDATA[%s]]></Description>
                        <MusicUrl><![CDATA[%s]]></MusicUrl>
                        <HQMusicUrl><![CDATA[%s]]></HQMusicUrl>
                        <ThumbMediaId><![CDATA[%s]]></ThumbMediaId>
                        </Music>
                      </xml>";
        $resultStr = sprintf($text_template, $to_user_name, $from_user_name, $time, $title, $description, $music_url, $HQ_music_url, $media_id);
        echo $resultStr;
    }

    private function httpRequest($url, $method, $data = null) {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        if ($method == "POST" && !empty($data)) {
            curl_setopt($curl, CURLOPT_POST, true);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_TIMEOUT, 500);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);

        $res = curl_exec($curl);
        curl_close($curl);

        return $res;
    }

}
